//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
/*
;***
;chkstk.asm - C stack checking routine
;
;       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
;
;Purpose:
;       Provides support for automatic stack checking in C procedures
;       when stack checking is enabled.
;
;******************************************************************************

;***
;_chkstk - check stack upon procedure entry
;
;Purpose:
;       Provide stack checking on procedure entry. Method is to simply probe
;       each page of memory required for the stack in descending order. This
;       causes the necessary pages of memory to be allocated via the guard
;       page scheme, if possible. In the event of failure, the OS raises the
;       _XCPT_UNABLE_TO_GROW_STACK exception.
;
;       NOTE:  Currently, the (EAX < MINPAGESIZE) code path falls through
;       to the "lastpage" label of the (EAX >= MINPAGESIZE) code path.  This
;       is small; a minor speed optimization would be to special case
;       this up top.  This would avoid the painful save/restore of
;       ecx and would shorten the code path by 4-6 instructions.
;
;Entry:
;       EAX = size of local frame
;
;Exit:
;       ESP = new stackframe, if successful
;
;Uses:
;       EAX
;
;Exceptions:
;       _XCPT_GUARD_PAGE_VIOLATION - May be raised on a page probe. NEVER TRAP
;                                    THIS!!!! It is used by the OS to grow the
;                                    stack on demand.
;       _XCPT_UNABLE_TO_GROW_STACK - The stack cannot be grown. More precisely,
;                                    the attempt by the OS memory manager to
;                                    allocate another guard page in response
;                                    to a _XCPT_GUARD_PAGE_VIOLATION has
;                                    failed.
;
;*****************************************************************************/

//==========================================================================
// Copyright (c) 2000-2004,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
//
// The original program was copied from Microsoft Visual Studio 6.0
// Enterprise Edition.  This file is adapted for Zee operating system.
//==========================================================================

#include <elatypes.h>

#define MINPAGESIZE 0x00001000

#if defined(_x86)
__declspec(naked) void __cdecl _chkstk(void)
{
    __asm {
        push    ecx                     ; save ecx

// codes below force ESP and EBP to align with 4 bytes, generate
//   a GP fault otherwise.
//
#if 0
        mov     ecx, esp
        test    ecx, 3
        jnz     AlignFail
        mov     ecx, ebp
        test    ecx, 3
        jnz     AlignFail
        jmp     AlignOk
AlignFail:
        xor     ecx, ecx
        mov     [ecx], 0
AlignOk:
#endif

        cmp     eax,MINPAGESIZE         ; more than one page requested?
        lea     ecx,[esp] + 8           ;   compute new stack pointer in ecx
                                        ;   correct for return address and
                                        ;   saved ecx
        jb      short lastpage          ; no

probepages:
        sub     ecx,MINPAGESIZE         ; yes, move down a page
        sub     eax,MINPAGESIZE         ; adjust request and...

        test    dword ptr [ecx],eax     ; ...probe it

        cmp     eax,MINPAGESIZE         ; more than one page requested?
        jae     short probepages        ; no

lastpage:
        sub     ecx,eax                 ; move stack down by eax
        mov     eax,esp                 ; save current tos and do a...

        test    dword ptr [ecx],eax     ; ...probe in case a page was crossed

        mov     esp,ecx                 ; set the new stack pointer

        mov     ecx,dword ptr [eax]     ; recover ecx
        mov     eax,dword ptr [eax + 4] ; recover return address

        push    eax                     ; prepare return address
                                        ; ...probe in case a page was crossed
        ret
    }
}

// C/C++ code can't over load function names, which was found in
// the original Microsoft assembly program.
//
__declspec(naked) void __cdecl _alloca_probe(void) {
    __asm jmp _chkstk
}

//_alloca_probe_16 : 16 byte aligned alloca
__declspec(naked) void __cdecl  _alloca_probe_16() {
    __asm
    {
        push    ecx
        lea     ecx, [esp] + 8          ; TOS before entering this function
        sub     ecx, eax                ; New TOS
        and     ecx, (16 - 1)           ; Distance from 16 bit align (align down)
        add     eax, ecx                ; Increase allocation size
        sbb     ecx, ecx                ; ecx = 0xFFFFFFFF if size wrapped around
        or      eax, ecx                ; cap allocation size on wraparound
        pop     ecx                     ; Restore ecx
        jmp     _chkstk
    }
}

//alloca_8: 8 byte aligned alloca
__declspec(naked) void __cdecl _alloca_probe_8() {
    __asm
    {
        push    ecx
        lea     ecx, [esp] + 8          ; TOS before entering this function
        sub     ecx, eax                ; New TOS
        and     ecx, (8 - 1)            ; Distance from 8 bit align (align down)
        add     eax, ecx                ; Increase allocation Size
        sbb     ecx, ecx                ; ecx = 0xFFFFFFFF if size wrapped around
        or      eax, ecx                ; cap allocation size on wraparound
        pop     ecx                     ; Restore ecx
        jmp     _chkstk
    }
}

#endif
